home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / gpt32src.zip / SCANNER.C < prev    next >
C/C++ Source or Header  |  1992-03-25  |  9KB  |  349 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: scanner.c,v 3.26 92/03/24 22:34:36 woo Exp Locker: woo $";
  3. #endif
  4.  
  5. /* GNUPLOT - scanner.c */
  6. /*
  7.  * Copyright (C) 1986, 1987, 1990, 1991, 1992   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Original Software:
  25.  *     Thomas Williams,  Colin Kelley.
  26.  * 
  27.  *   Gnuplot 2.0 additions:
  28.  *       Russell Lang, Dave Kotz, John Campbell.
  29.  *
  30.  *   Gnuplot 3.0 additions:
  31.  *       Gershon Elber and many others.
  32.  * 
  33.  * Send your comments or suggestions to 
  34.  *  info-gnuplot@ames.arc.nasa.gov.
  35.  * This is a mailing list; to join it send a note to 
  36.  *  info-gnuplot-request@ames.arc.nasa.gov.  
  37.  * Send bug reports to
  38.  *  bug-gnuplot@ames.arc.nasa.gov.
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include "plot.h"
  44.  
  45. #ifdef AMIGA_AC_5
  46. #define O_RDONLY    0
  47. int open(const char * _name, int _mode, ...);
  48. int close(int);
  49. #endif
  50.  
  51. #ifdef vms
  52.  
  53. #include stdio
  54. #include descrip
  55. #include errno
  56.  
  57. #define MAILBOX "PLOT$MAILBOX"
  58. #define pclose(f) fclose(f)
  59.  
  60. #endif /* vms */
  61.  
  62.  
  63. #define isident(c) (isalnum(c) || (c) == '_')
  64.  
  65. #ifndef STDOUT
  66. #define STDOUT 1
  67. #endif
  68.  
  69. #define LBRACE '{'
  70. #define RBRACE '}'
  71.  
  72. #define APPEND_TOKEN {token[t_num].length++; current++;}
  73.  
  74. #define SCAN_IDENTIFIER while (isident(expression[current + 1]))\
  75.                 APPEND_TOKEN
  76.  
  77. extern struct lexical_unit token[MAX_TOKENS];
  78.  
  79. static int t_num;    /* number of token I'm working on */
  80.  
  81. char *strcat(), *strcpy(), *strncpy();
  82.  
  83. /*
  84.  * scanner() breaks expression[] into lexical units, storing them in token[].
  85.  *   The total number of tokens found is returned as the function value.
  86.  *   Scanning will stop when '\0' is found in expression[], or when token[]
  87.  *     is full.
  88.  *
  89.  *     Scanning is performed by following rules:
  90.  *
  91.  *    Current char    token should contain
  92.  *     -------------    -----------------------
  93.  *    1.  alpha,_    all following alpha-numerics
  94.  *    2.  digit    0 or more following digits, 0 or 1 decimal point,
  95.  *                0 or more digits, 0 or 1 'e' or 'E',
  96.  *                0 or more digits.
  97.  *    3.  ^,+,-,/    only current char
  98.  *        %,~,(,)
  99.  *        [,],;,:,
  100.  *        ?,comma
  101.  *    4.  &,|,=,*    current char; also next if next is same
  102.  *    5.  !,<,>    current char; also next if next is =
  103.  *    6.  ", '    all chars up until matching quote
  104.  *    7.  #        this token cuts off scanning of the line (DFK).
  105.  *
  106.  *            white space between tokens is ignored
  107.  */
  108. scanner(expression)
  109. char expression[];
  110. {
  111. register int current;    /* index of current char in expression[] */
  112. register int quote;
  113. char brace;
  114.  
  115.     for (current = t_num = 0;
  116.         t_num < MAX_TOKENS && expression[current] != '\0';
  117.         current++) {
  118. again:
  119.         if (isspace(expression[current]))
  120.             continue;                        /* skip the whitespace */
  121.         token[t_num].start_index = current;
  122.         token[t_num].length = 1;
  123.         token[t_num].is_token = TRUE;    /* to start with...*/
  124.  
  125.         if (expression[current] == '`') {
  126.             substitute(&expression[current],MAX_LINE_LEN - current);
  127.             goto again;
  128.         }
  129.         /* allow _ to be the first character of an identifier */
  130.         if (isalpha(expression[current]) || expression[current] == '_') {
  131.             SCAN_IDENTIFIER;
  132.         } else if (isdigit(expression[current]) || expression[current] == '.'){
  133.             token[t_num].is_token = FALSE;
  134.             token[t_num].length = get_num(&expression[current]);
  135.             current += (token[t_num].length - 1);
  136.         } else if (expression[current] == LBRACE) {
  137.             token[t_num].is_token = FALSE;
  138.             token[t_num].l_val.type = CMPLX;
  139.             if ((sscanf(&expression[++current],"%lf , %lf %c",
  140.                 &token[t_num].l_val.v.cmplx_val.real,
  141.                 &token[t_num].l_val.v.cmplx_val.imag,
  142.                 &brace) != 3) || (brace != RBRACE))
  143.                     int_error("invalid complex constant",t_num);
  144.             token[t_num].length += 2;
  145.             while (expression[++current] != RBRACE) {
  146.                 token[t_num].length++;
  147.                 if (expression[current] == '\0')            /* { for vi % */
  148.                     int_error("no matching '}'", t_num);
  149.             }
  150.         } else if (expression[current] == '\'' || expression[current] == '\"'){
  151.             token[t_num].length++;
  152.             quote = expression[current];
  153.             while (expression[++current] != quote) {
  154.                 if (!expression[current]) {
  155.                     expression[current] = quote;
  156.                     expression[current+1] = '\0';
  157.                     break;
  158.                 } else
  159.                     token[t_num].length++;
  160.             }
  161.         } else switch (expression[current]) {
  162.              case '#':        /* DFK: add comments to gnuplot */
  163.                   goto endline; /* ignore the rest of the line */
  164.             case '^':
  165.             case '+':
  166.             case '-':
  167.             case '/':
  168.             case '%':
  169.             case '~':
  170.             case '(':
  171.             case ')':
  172.             case '[':
  173.             case ']':
  174.             case ';':
  175.             case ':':
  176.             case '?':
  177.             case ',':
  178.                 break;
  179.             case '&':
  180.             case '|':
  181.             case '=':
  182.             case '*':
  183.                 if (expression[current] == expression[current + 1])
  184.                     APPEND_TOKEN;
  185.                 break;
  186.             case '!':
  187.             case '<':
  188.             case '>':
  189.                 if (expression[current + 1] == '=')
  190.                     APPEND_TOKEN;
  191.                 break;
  192.             default:
  193.                 int_error("invalid character",t_num);
  194.             }
  195.         ++t_num;    /* next token if not white space */
  196.     }
  197.  
  198. endline:                    /* comments jump here to ignore line */
  199.  
  200. /* Now kludge an extra token which points to '\0' at end of expression[].
  201.    This is useful so printerror() looks nice even if we've fallen off the
  202.    line. */
  203.  
  204.         token[t_num].start_index = current;
  205.         token[t_num].length = 0;
  206.     return(t_num);
  207. }
  208.  
  209.  
  210. get_num(str)
  211. char str[];
  212. {
  213. double atof();
  214. register int count = 0;
  215. long atol();
  216. register long lval;
  217.  
  218.     token[t_num].is_token = FALSE;
  219.     token[t_num].l_val.type = INT;        /* assume unless . or E found */
  220.     while (isdigit(str[count]))
  221.         count++;
  222.     if (str[count] == '.') {
  223.         token[t_num].l_val.type = CMPLX;
  224.         while (isdigit(str[++count]))    /* swallow up digits until non-digit */
  225.             ;
  226.         /* now str[count] is other than a digit */
  227.     }
  228.     if (str[count] == 'e' || str[count] == 'E') {
  229.         token[t_num].l_val.type = CMPLX;
  230. /* modified if statement to allow + sign in exponent
  231.    rjl 26 July 1988 */
  232.         count++;
  233.         if (str[count] == '-' || str[count] == '+')
  234.             count++;
  235.         if (!isdigit(str[count])) {
  236.             token[t_num].start_index += count;
  237.             int_error("expecting exponent",t_num);
  238.         }
  239.         while (isdigit(str[++count]))
  240.             ;
  241.     }
  242.     if (token[t_num].l_val.type == INT) {
  243.          lval = atol(str);
  244.         if ((token[t_num].l_val.v.int_val = lval) != lval)
  245.             int_error("integer overflow; change to floating point",t_num);
  246.     } else {
  247.         token[t_num].l_val.v.cmplx_val.imag = 0.0;
  248.         token[t_num].l_val.v.cmplx_val.real = atof(str);
  249.     }
  250.     return(count);
  251. }
  252.  
  253.  
  254. #ifdef MSDOS
  255.  
  256. #ifdef __ZTC__
  257. substitute(char *str,int max)
  258. #else
  259. substitute()
  260. #endif
  261. {
  262.     int_error("substitution not supported by MS-DOS!",t_num);
  263. }
  264.  
  265. #else /* MSDOS */
  266. #ifdef AMIGA_LC_5_1
  267. substitute()
  268. {
  269.     int_error("substitution not supported by AmigaDOS!",t_num);
  270. }
  271.  
  272. #else /* AMIGA_LC_5_1 */
  273.  
  274. substitute(str,max)            /* substitute output from ` ` */
  275. char *str;
  276. int max;
  277. {
  278. register char *last;
  279. register int i,c;
  280. register FILE *f;
  281. #ifdef AMIGA_AC_5
  282. int fd;
  283. #else
  284. FILE *popen();
  285. #endif
  286. static char pgm[MAX_LINE_LEN+1],output[MAX_LINE_LEN+1];
  287.  
  288. #ifdef vms
  289. int chan;
  290. static $DESCRIPTOR(pgmdsc,pgm);
  291. static $DESCRIPTOR(lognamedsc,MAILBOX);
  292. #endif /* vms */
  293.  
  294.     i = 0;
  295.     last = str;
  296.     while (*(++last) != '`') {
  297.         if (*last == '\0')
  298.             int_error("unmatched `",t_num);
  299.         pgm[i++] = *last;
  300.     }
  301.     pgm[i] = '\0';        /* end with null */
  302.     max -= strlen(last);    /* max is now the max length of output sub. */
  303.   
  304. #ifdef vms
  305.       pgmdsc.dsc$w_length = i;
  306.        if (!((vaxc$errno = sys$crembx(0,&chan,0,0,0,0,&lognamedsc)) & 1))
  307.            os_error("sys$crembx failed",NO_CARET);
  308.    
  309.        if (!((vaxc$errno = lib$spawn(&pgmdsc,0,&lognamedsc,&1)) & 1))
  310.            os_error("lib$spawn failed",NO_CARET);
  311.    
  312.        if ((f = fopen(MAILBOX,"r")) == NULL)
  313.            os_error("mailbox open failed",NO_CARET);
  314. #else /* vms */
  315. #ifdef AMIGA_AC_5
  316.       if ((fd = open(pgm,"O_RDONLY")) == -1)
  317. #else
  318.       if ((f = popen(pgm,"r")) == NULL)
  319. #endif
  320.           os_error("popen failed",NO_CARET);
  321. #endif /* vms */
  322.  
  323.     i = 0;
  324.     while ((c = getc(f)) != EOF) {
  325.         output[i++] = ((c == '\n') ? ' ' : c);    /* newlines become blanks*/
  326.         if (i == max) {
  327. #ifdef AMIGA_AC_5
  328.             (void) close(fd);
  329. #else
  330.             (void) pclose(f);
  331. #endif
  332.             int_error("substitution overflow", t_num);
  333.         }
  334.     }
  335. #ifdef AMIGA_AC_5
  336.     (void) close(fd);
  337. #else
  338.     (void) pclose(f);
  339. #endif
  340.     if (i + strlen(last) > max)
  341.         int_error("substitution overflowed rest of line", t_num);
  342.     (void) strncpy(output+i,last+1,MAX_LINE_LEN-i);
  343.                                     /* tack on rest of line to output */
  344.     (void) strcpy(str,output);                /* now replace ` ` with output */
  345.     screen_ok = FALSE;
  346. }
  347. #endif /* AMIGA_LC_5_1 */
  348. #endif /* MS-DOS */
  349.